package com.net.xpay.common.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayOpenAgentCommonSignResponse;
import com.alipay.api.response.AlipayOpenAgentConfirmResponse;
import com.alipay.api.response.AlipayOpenAgentCreateResponse;
import com.alipay.api.response.AlipayOpenSpIsvSignauthCreateResponse;
import com.net.xpay.common.domain.AlipayUserSignAuthRecord;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.enums.open.AuthStatus;
import com.net.xpay.common.enums.user.AlipayUserSignAuthRecordStatus;
import com.net.xpay.common.manager.AlipayUserSignAuthRecordManager;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.model.SignAuthModel;
import com.net.xpay.common.validator.AlipayUserSignValidator;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.domain.AlipayUser;
import com.net.xpay.core.enums.AlipayUserStatus;
import com.net.xpay.core.manager.AlipayUserManager;
import com.net.xpay.core.model.AlipayUserSearchModel;
import com.net.common.annotation.WriteTransactional;
import com.net.common.exception.BusinessException;
import com.net.common.util.SerializationUtil;
import com.net.xpay.alipay.PoseidonAlipayClient;
import com.net.xpay.alipay.model.CreateAlipayOpenSpIsvSignauthModel;
import com.net.xpay.alipay.model.CreateOpenAgentModel;
import com.net.xpay.alipay.model.SignOpenAgentCommonModel;
import com.net.xpay.common.service.AlipayUserSignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

@Slf4j
@Service
public class AlipayUserSignServiceImpl implements AlipayUserSignService {

    @Autowired
    private AlipayUserSignValidator alipayUserSignValidator;

    @Autowired
    private PoseidonAlipayClient xpayAlipayClient;

    @Autowired
    private AlipayUserSignAuthRecordManager alipayUserSignAuthRecordManager;

    @Autowired
    private AlipayUserManager alipayUserManager;

    @Autowired
    private UserManager userManager;

    @Override
    @WriteTransactional
    public AlipayUserSignAuthRecord signAuth(User user, SignAuthModel signAuthModel) throws AlipayApiException {
        alipayUserSignValidator.validateSignAuth(user, signAuthModel);

        //判断用户是否已经签约过，签约过了就直接走授权行为
        boolean isSigned = checkAlipayUserSignStatus(user, signAuthModel.getAlipayNickName());
        if (isSigned) {
            //直接走授权
            return directAuth(user, signAuthModel);
        } else {
            //走签约授权一体化流程
            try {
                return signAndAuth(user, signAuthModel);
            } catch (BusinessException e) {
                //已签约 只需要走授权
                if (PoseidonErrorCode.ANT_PRODUCT_CONFLICT.equals(e.getErrorCode())) {
                    return directAuth(user, signAuthModel);
                }
                throw e;
            }
        }
    }

    //走签约授权一体化流程
    private AlipayUserSignAuthRecord signAndAuth(User user, SignAuthModel signAuthModel) throws AlipayApiException {
        //开启代签约事务接口 获取事务号
        String batchNo = createAlipayOpenAgent(user, signAuthModel);

        //创建签约单
        signAlipayOpenAgentCommon(user, signAuthModel, batchNo);

        //提交代签约事务
        String orderNo = confirmAlipayOpenAgent(user, signAuthModel, batchNo);

        //申请签约授权一体化
        String orderId = createAlipayOpenSpIsvSignauth(user, signAuthModel, orderNo);

        AlipayUserSignAuthRecord record = saveAuthRecord(user, orderId, batchNo, signAuthModel);

        //创建或跟新AlipayUser
        saveOrUpdateAlipayUser(user, signAuthModel, record.getIsvBizId());

        return record;
    }

    //直接走授权
    private AlipayUserSignAuthRecord directAuth(User user, SignAuthModel signAuthModel) throws AlipayApiException {
        //申请签约授权一体化
        String orderId = createAlipayOpenSpIsvSignauth(user, signAuthModel, null);
        String isvBizId = user.getId() + "-" + System.currentTimeMillis();//这个不能改和之前的方式一样的，改了消息推送后的处理逻辑会出错
        AlipayUserSignAuthRecord record = alipayUserSignAuthRecordManager.findByAlipayNickName(user.getId(), signAuthModel.getAlipayNickName());
        if (record == null) {
            //老用户走的老方式签约授权的 这种签约状态应该是FINISH
            record = new AlipayUserSignAuthRecord();
            record.setStatus(AlipayUserSignAuthRecordStatus.FINISH);
            record.setSignSubmitTime(LocalDateTime.now());
            record.setContactMobile(signAuthModel.getContactMobile());
            record.setContactName(signAuthModel.getContactName());
            record.setContactEmail(signAuthModel.getContactEmail());
            record.setIsAuditTimeout(0);
            record.setUserId(user.getId());
            record.setAlipayNickName(signAuthModel.getAlipayNickName());
            record.setBizNo(orderId);//消息推送过来的是这个事务号
            record.setIsvBizId(isvBizId);//存给alipayUser表的，保持和之前的风格一致，统一处理消息推送逻辑
            record.setAuthStatus(AuthStatus.NO);
            record.setAuthSubmitTime(LocalDateTime.now());
            alipayUserSignAuthRecordManager.save(record);
        } else {
            record.setAuthStatus(AuthStatus.NO);
            record.setAuthSubmitTime(LocalDateTime.now());
            record.setBizNo(orderId);
            record.setIsvBizId(isvBizId);
            record.setIsAuditTimeout(0);
            alipayUserSignAuthRecordManager.update(record);
        }

        //创建或跟新AlipayUser
        saveOrUpdateAlipayUser(user, signAuthModel, isvBizId);

        return record;
    }

    private void saveOrUpdateAlipayUser(User user, SignAuthModel signAuthModel, String isvBizId) {
        Long userId = user.getId();
        String alipayNickName = signAuthModel.getAlipayNickName();
        AlipayUser alipayUser = alipayUserManager.findByAlipayNickName(userId, alipayNickName);
        if (alipayUser == null) {
            alipayUser = AlipayUser.getInstance();
            alipayUser.setUserId(userId);
            alipayUser.setMobile(user.getMobile());
            alipayUser.setAlipayNickName(alipayNickName);
            // 异步消息需要根据isvBizId来获取对应token
            alipayUser.setIsvBizId(isvBizId);
            alipayUser.setStatus(AlipayUserStatus.NO);
            alipayUser.setIsDeleted(0);
            alipayUserManager.save(alipayUser);

            //将第一个绑定的号作为主支付宝账号
            AlipayUserSearchModel searchModel = new AlipayUserSearchModel();
            searchModel.setUserId(user.getId());
            long count = alipayUserManager.searchCount(searchModel);
            if (count == 1L) {
                User selectedUser = userManager.getById(user.getId());
                selectedUser.setAlipayNickName(alipayNickName);
                selectedUser.setAlipayUserId(alipayUser.getId());
                userManager.updateByPrimaryKeyWithVersion(selectedUser);
            }
        } else {
            alipayUser.setStatus(AlipayUserStatus.NO);
            alipayUser.setIsvBizId(isvBizId);
            alipayUser.setIsDeleted(0);
            alipayUserManager.updateByPrimaryKeyWithVersion(alipayUser);
        }
    }

    private boolean checkAlipayUserSignStatus(User user, String alipayNickName) {
        //老用户签约过的直接走授权 因为已经签约过了
        AlipayUser alipayUser = alipayUserManager.findByAlipayNickName(user.getId(), alipayNickName);
        if (alipayUser != null && AlipayUserStatus.YES == alipayUser.getStatus()) {
            return true;
        }

        AlipayUserSignAuthRecord record = alipayUserSignAuthRecordManager.findByAlipayNickName(user.getId(), alipayNickName);
        if (record == null) {
            return false;
        }
        if (record.getStatus() == AlipayUserSignAuthRecordStatus.FINISH) {
            return true;
        }
        if (record.getStatus() == AlipayUserSignAuthRecordStatus.INIT || record.getStatus() == AlipayUserSignAuthRecordStatus.UNCONFIRM) {
            throw new BusinessException(PoseidonErrorCode.SIGN_AUTH_IS_SUBMIT, "签约授权事务已在处理中");
        }

        return false;
    }

    private AlipayUserSignAuthRecord saveAuthRecord(User user, String orderId, String batchNo, SignAuthModel signAuthModel) {
        boolean isUpdate = true;
        AlipayUserSignAuthRecord record = alipayUserSignAuthRecordManager.findByAlipayNickName(user.getId(), signAuthModel.getAlipayNickName());
        if (record == null) {
            record = new AlipayUserSignAuthRecord();
            isUpdate = false;
        }

        record.setBatchNo(batchNo);
        record.setStatus(AlipayUserSignAuthRecordStatus.INIT);
        record.setIsAuditTimeout(0);
        record.setSignSubmitTime(LocalDateTime.now());
        record.setContactMobile(signAuthModel.getContactMobile());
        record.setContactName(signAuthModel.getContactName());
        record.setContactEmail(signAuthModel.getContactEmail());
        record.setUserId(user.getId());
        record.setAlipayNickName(signAuthModel.getAlipayNickName());
        record.setBizNo(orderId);//消息推送过来的是这个事务号
        String isvBizId = user.getId() + "-" + System.currentTimeMillis();//这个不能改和之前的方式一样的，改了消息推送后的处理逻辑会出错
        record.setIsvBizId(isvBizId);//存给alipayUser表的，保持和之前的风格一致，统一处理消息推送逻辑
        record.setAuthStatus(AuthStatus.NO);
        record.setAuthSubmitTime(LocalDateTime.now());

        if (isUpdate) {
            alipayUserSignAuthRecordManager.update(record);
        } else {
            alipayUserSignAuthRecordManager.save(record);
        }

        return record;
    }

    private String createAlipayOpenSpIsvSignauth(User user, SignAuthModel signAuthModel, String orderNo) throws AlipayApiException {
        CreateAlipayOpenSpIsvSignauthModel createAlipayOpenSpIsvSignauthModel = new CreateAlipayOpenSpIsvSignauthModel();
        createAlipayOpenSpIsvSignauthModel.setMerchantLogonId(signAuthModel.getAlipayNickName());
        createAlipayOpenSpIsvSignauthModel.setSignOrderNo(orderNo);
        AlipayOpenSpIsvSignauthCreateResponse resp = xpayAlipayClient.createAlipayOpenSpIsvSignauth(createAlipayOpenSpIsvSignauthModel);
        if (!resp.isSuccess()) {
            log.info("signAlipayOpenAgentCommon failed|model={}|userId={}|orderNo={}", SerializationUtil.obj2String(signAuthModel), user.getId(), orderNo);
            throw new BusinessException(PoseidonErrorCode.BUSINESS_ERROR, "签约失败:" + resp.getSubMsg());
        }
        return resp.getOrderId();
    }

    private String confirmAlipayOpenAgent(User user, SignAuthModel signAuthModel, String batchNo) throws AlipayApiException {
        AlipayOpenAgentConfirmResponse resp = xpayAlipayClient.confirmAlipayOpenAgent(batchNo);
        if (!resp.isSuccess()) {
            log.info("confirmAlipayOpenAgent failed|model={}|userId={}|batchNo={}", SerializationUtil.obj2String(signAuthModel), user.getId(), batchNo);
            throw new BusinessException(PoseidonErrorCode.BUSINESS_ERROR, "签约失败:" + resp.getSubMsg());
        }
        return resp.getOrderNo();
    }

    private boolean signAlipayOpenAgentCommon(User user, SignAuthModel signAuthModel, String batchNo) throws AlipayApiException {
        SignOpenAgentCommonModel signOpenAgentCommonModel = new SignOpenAgentCommonModel();
        signOpenAgentCommonModel.setMccCode("C_C09_5942");//书籍类
        signOpenAgentCommonModel.setBatchNo(batchNo);
        signOpenAgentCommonModel.setProductCode("BATCH_API_TO_ACC");//批量有密
        AlipayOpenAgentCommonSignResponse response = xpayAlipayClient.signAlipayOpenAgentCommon(signOpenAgentCommonModel);
        if (!response.isSuccess()) {
            log.info("signAlipayOpenAgentCommon failed|model={}|userId={}|batchNo={}", SerializationUtil.obj2String(signAuthModel), user.getId(), batchNo);
            //产品已签约 或者已经签约了同类产品
            if (response.getSubCode().equals("ANT_PRODUCT_CONFLICT")) {
                throw new BusinessException(PoseidonErrorCode.ANT_PRODUCT_CONFLICT, response.getSubMsg());
            }
            throw new BusinessException(PoseidonErrorCode.BUSINESS_ERROR, "签约失败:" + response.getSubMsg());
        }
        return true;
    }

    private String createAlipayOpenAgent(User user, SignAuthModel signAuthModel) throws AlipayApiException {
        CreateOpenAgentModel createOpenAgentModel = new CreateOpenAgentModel();
        createOpenAgentModel.setAccount(signAuthModel.getAlipayNickName());
        CreateOpenAgentModel.ContactModel contactModel = new CreateOpenAgentModel.ContactModel();
        contactModel.setContactName(signAuthModel.getContactName());
        contactModel.setContactEmail(signAuthModel.getContactEmail());
        contactModel.setContactMobile(signAuthModel.getContactMobile());
        createOpenAgentModel.setContactInfo(contactModel);
        AlipayOpenAgentCreateResponse resp = xpayAlipayClient.createAlipayOpenAgent(createOpenAgentModel);
        if (!resp.isSuccess()) {
            log.info("createAlipayOpenAgent failed|model={}|userId={}", SerializationUtil.obj2String(signAuthModel), user.getId());
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "签约失败:" + resp.getSubMsg());
        }
        return resp.getBatchNo();
    }

}
